-- require "geometry"
local nl=require "luaNumeric"
require "luaFDTD3D"
local unity=require "luaUnity"
require "Q2DViewerEx"
require 'unity'

local RCSPost = require"RCS.luaRCSPost"
local RCS = require "RCS.luaRCSModel"


--===========================================================================--
--初始化参数
local MSRCSSolver={

	path = ' ';                           --主目录:                c:/almond/
	projectPath = '';                  -- 总工程文件目录:  c:/almond/almond.gap
	resultsPath = 'MonoRCS';     -- 计算结果目录:      c:/almond/almond-RCS/
	gapsPath = 'gaps';               -- 计算结果目录:      c:/almond/almond-GAPs/
	geometryFilePath = '';          -- 导入模型目录:      c:/almond.stp
	fileName = 'rcs';                  --文件名:                c:/almond-details
	name = '';                           --文件名:                almond
	rcsProjectStem = '';              --
	name = 'RCS';
	
	epsr = 3;
	tans = 0.001;
	bPEC = false;

	minFreq = 1;
	maxFreq = 5;
	numFreq = 6;
	bFreqList = false;
	freqList = '(1,10,10)';
	meshFreq = 10;
	accuracy = -30;
	maxSteps = 10000;
	numThreads = 20;
	bSaveNearfields = false;
	
	minAngle = 0;
	maxAngle = 5;
	numAngle = 6;
	bAngleList = false;
	angleList = '(-90,90,91)';

	polarHH = true;
	polarVV = false;
	elevationAngle = 0;
	
	results = {};
	
	set_settings_str = Gallop.set_settings_str;
	get_settings_str = Gallop.get_settings_str;
	
	--polars = {'HH','VV'};

};
--===========================================================================--


--===========================================================================--
--创建表和创建元表
function MSRCSSolver:new (o)
	o = o or {};
	self.__index = self;	
	setmetatable(o,self)
	o:regist_funcs_to_gallop();
	o.init_strs = o:get_settings_str();
	return o;
end
--===========================================================================--


--===========================================================================--
--注册全局函数
function MSRCSSolver:regist_funcs_to_gallop()
	Gallop.init_funcs['MSRCSApp'] = function()
		local str = self.init_strs;
		assert( type('str')=='string', 'MonoStaticRCS Plugin init string error' );
		if str ~= '' then
			Gallop.MSRCSApp:set_settings_str(str)
		end
		Gallop.MSRCSApp:update_parameters_to_ui();
	end;
	
	Gallop.load_funcs['MSRCSApp'] = function()
		local str = Geometry.get_setting( 'MSRCSApp.Settings' )
		if str ~= '' then
			Gallop.MSRCSApp:set_settings_str(str)
		end
		Gallop.MSRCSApp:update_parameters_to_ui();
		Gallop.MSRCSApp:init_parameters()
		Gallop.MSRCSApp:run_model_post1();
	end;
	
	Gallop.presave_funcs['MSRCSApp'] = function()
		Gallop.MSRCSApp:update_parameters_from_ui()
		local str = Gallop.MSRCSApp:get_settings_str();
		Geometry.set_setting( 'MSRCSApp.Settings', str );
	end;
end
--===========================================================================--


--===========================================================================--
-- 保存和读取函数
function MSRCSSolver:set_settings_str(str)
	Gallop.set_settings_str(self,str);
	self.results = undump_t(self.strResults);
	self.strResults = nil;
end

function MSRCSSolver:get_settings_str()
	self.strResults = dump_t(self.results,'');
	local str = Gallop.get_settings_str(self);
	self.strResults = nil;
	return str;
end
--===========================================================================--


--===========================================================================--
--ui交互函数
function MSRCSSolver:update_parameters_from_ui()
end

function MSRCSSolver:update_parameters_to_ui()
end

function MSRCSSolver:update_results_path_to_ui()
end

function MSRCSSolver:update_progress_bar(per)
end
--===========================================================================--

--===========================================================================--
function MSRCSSolver:set_solver()
	self:update_solver_settings_from_ui()
	
	assert( self.farbox_min_freq <= self.farbox_max_freq, '求解频率设置错误')
	assert( self.mesh_freq >= 1e-6, '剖分频率设置错误')
	Geometry.Mesh.mesh_freq(self.mesh_freq)
	local lambda = c0/(self.mesh_freq * Geometry.ref_units_freq() ) / Geometry.ref_units_dim();
	Geometry.remove_all_objects('farbox');
	Geometry.Parameters.add_variable('dext',''..lambda/4,'空气盒子与结构之间的间距');
	Geometry.Parameters.set_variable('dext',''..lambda/4);
	
	self:set_airbox();
	
	Geometry.Boundaries.boundary(UPML,UPML,UPML,UPML,UPML,UPML);
	Geometry.ref_units(mm,GHz,ns)
	local bbox = Geometry.bbox()
	
	assert( bbox:size() > 0, '没有任何几何结构' );

	local farbox = Geometry.object( "fbox" );
	if farbox == nil then 
		farbox = Geometry.NewNear2FarFieldBox("fbox") 
		Geometry.AddProbe(farbox);
	end
	farbox:freq( self.farbox_min_freq,self.farbox_max_freq,self.farbox_num_freq );
	farbox:pt1( bbox:xmin() .. '-dext', bbox:ymin() .. '-dext', bbox:zmin() .. '-dext' );
	farbox:pt2( bbox:xmax() .. '+dext', bbox:ymax() .. '+dext',bbox:zmax() .. '+dext' );
	
	farbox:angle_theta( 90,90,1);
	farbox:angle_phi( 0,360,361);


	if self.sig == nil then
		self:set_signal();
	end
	farbox:signal(self.sig)
	
end
--===========================================================================--

--===========================================================================--
--设置参数
function MSRCSSolver:set_parameters(
			path,
			m_minAngle,m_maxAngle,m_numAngle,
			m_epsr,m_tans,
			m_minFreq,m_maxFreq,m_numFreq,
			m_meshFreq,
			m_maxSteps,
			m_accuracy,
			m_polarHH,
			m_polarVV,
			bPEC,
			bFreqList,
			freqList,
			numThreads,
			elevation_angle
		)
		print( "set_parameters" );

		self.bPEC = bPEC;

		-- self.path = path;		
		self.epsr = m_epsr;
		self.tans = m_tans;
		self.minFreq = m_minFreq;
		self.maxFreq = m_maxFreq;
		
		self.meshFreq = m_meshFreq;
		self.maxSteps = m_maxSteps;
		self.accuracy = m_accuracy;
		self.bFreqList = bFreqList;
		self.freqList = freqList;
		self.numThreads = numThreads;
		self.elevationAngle = elevation_angle;
		
		self:init_parameters()		
		self:update_parameters_to_ui();
end
--===========================================================================--

--===========================================================================--
--初始化参数
function MSRCSSolver:init_parameters()
		
	if self.polarHH==true then
		self.polars = {"HH"};
	end
	if self.polarVV==true then
		self.polars  = {"VV"};
	end
	if self.polarHH==true and self.polarVV==true then
		self.polars  = {"HH","VV"};
	end	

	self.probe_freq = nl.LinearSpace(self.minFreq,self.maxFreq,self.numFreq);

	
	local minFreq = math.min( self.minFreq, self.maxFreq );
	local maxFreq = math.max( self.minFreq, self.maxFreq );
	self.minFreq = minFreq;
	self.maxFreq = maxFreq;
	
	minFreq = self.minFreq*0.8;
	maxFreq = self.maxFreq*1.2;
		
	if self.bFreqList==true then
		local farbox = Geometry.Near2FarFieldBox:new("fbox")
		farbox:freq( self.freqList );
		local list = farbox:freq();
		assert(#list>0, '频率设置错误')
		self.probe_freq = list;
		minFreq = nl.min( list );
		maxFreq = nl.max( list );
	end
	--print('probe_freq:',self.probe_freq);

	local cF = (minFreq+maxFreq)/2.0;
	self.src_min_freq = math.min( minFreq*0.8, cF*0.8)
	self.src_max_freq = math.max( maxFreq*1.2, cF*1.2)
	
	self.scan_angles = nl.LinearSpace(self.minAngle,self.maxAngle,self.numAngle);

	if self.bAngleList==true then
		self.scan_angles = nl.new_vector(self.angleList);
		--print(self.scan_angles)
		self.angleList1 = self.angleList;
	else
		self.angleList1 = '('.. self.minAngle ..','.. self.maxAngle ..','.. self.numAngle .. ')';
	end
	
	self.polar_angles = '';
	for k,v in pairs(self.polars) do 
		if k>1 then
			self.polar_angles = self.polar_angles .. ';';
		end
		if v == 'HH' then
			self.polar_angles = self.polar_angles .. '90';
		else
			self.polar_angles = self.polar_angles .. '0';
		end		
	end
end
--===========================================================================--

--===========================================================================--
function MSRCSSolver:print_paths()
	 print( 'path:',self.path )
	 print( 'name:',self.name )
	 --print( 'geometryFileName:',self.geometryFileName )
	 print( 'projectPath:',self.projectPath )
	 print( 'resultsPath:',self.resultsPath )
	 print( 'gapsPath:',self.gapsPath )	 
end
--===========================================================================--

--===========================================================================--
--初始化目录
function MSRCSSolver:get_path_from_project()
	self.projectPath = Geometry.get_project_path_utf8(  );
	assert( self.projectPath~='', "请先保存工程") 
	self.stemPath = Geometry.get_project_stem_utf8();
	
	self.path =  strippath(self.projectPath) .. '/';
	self.resultsPath = self.stemPath .. '-RCS/';	
	self.gapsPath = self.stemPath ..'-GAPs/';	
	self.name = getFilenameWithoutExt( self.projectPath );

	self:print_paths();
	unity.mkdir(self.resultsPath)
	unity.mkdir(self.gapsPath)
end
--===========================================================================--


--===========================================================================--
--导入几何结构，并设置材料
function MSRCSSolver:create_geometry()

	self:update_parameters_from_ui()	
	print( "Create geometry from file and set material properties" );	
	Geometry.clear_all();
	local ufreq = Geometry.ref_units_freq();
	
	------------------------------------------------------------------------------------------------------------
	--Materials：
	if self.bPEC then
		self.material = Geometry.GetMaterial("PEC")
	else
		self.material = Geometry.NewDebyeMaterial("材料")  --deby指的是色散模型
		self.material:fill_color(0.5,0.5,0)
		self.material:fit_tangent_delta_e(ufreq*(self.minFreq+self.maxFreq)/2.0,self.epsr,self.tans)
	end
	----------------------------------------------------------------------------------------------------------	

	------------------------------------------------------------------------------------------------------------	
	--导入几何模型（外罩）：stp
	--local w2 = Geometry.load_step{path = self.geometryFilePathUtf8 }
	local w2 = Geometry.load( self.geometryFilePathUtf8 )
	w2:name( "散射体" )
	w2:fill_color(0.6,0,0.8,0.4)
	if w2:shape_type()=="PrivateObj" then
		w2:triangulate(3)
	end
	w2:material( self.material )
	w2:soft_edge();
	self.loaded_shape = w2;
	Geometry.AddShape(self.loaded_shape)
	--------------------------- ---------------------------------------------------------------------------------
	
	---------------------------
	--设置透视视角
	Gallop.View:perspective_view();
	---------------------------

	---------------------------
	--清空所有计算模型
	self.results = {};
	---------------------------
	
	self:update_progress_bar(0)
end
--===========================================================================--

--===========================================================================--
--创建FDTD求解RCS模型
function MSRCSSolver:create_calculation_model()	

	self:update_parameters_from_ui()
	self:init_parameters()

	local ufreq = Geometry.ref_units_freq();	
	local angs = self.scan_angles;
	local eang = self.elevationAngle;	
	local ang = angs[1];
	local polar = self.polars[1];
	
	
	self:create_paras();
	self:set_paras();
	
	print( "Create calculation model" );	
	local mlist = Geometry.MaterialList();
	local list = Geometry.shapes_list();	
	local grabbers = Geometry.objects('Grabber');
	local vars = Geometry.Parameters.get_variables_list();
	
	local path = Geometry.get_project_path();
	
	--Geometry.clear_all();	
	
	self:set_airbox();
	
	
	self:set_source()
	
	self:set_farbox()
	
	self:set_nearfields();
	
	self:set_solver();
	
	self:create_directions();
	
	self:set_grabber()

	
	print('name:',self.name.."-"..polar.."-ang("..ang..")");
	print('path:',self.resultsPath);
	


	--Gallop.ParametersSweep:set_solver_settings( stepStr  );
	--Gallop.ParametersSweep:set_pre_settings( preStr);
	--Gallop.ParametersSweep:set_post_settings( postStr);
	
	---------------------------
	--设置透视视角
	Gallop.View:perspective_view();
	---------------------------	
	
	Geometry.synchronize();
	
	if path~='' and type(path) == 'string' then
		--print( 'set path:', path )
		--Geometry.set_project_path(path);
	end
end
--===========================================================================--

--===========================================================================--
--设置求解器
function MSRCSSolver:set_solver()
	Geometry.Boundaries.boundary(UPML,UPML,UPML,UPML,UPML,UPML );
	Geometry.Mesh.mesh_freq( self.meshFreq )
	Geometry.Solver.threads( self.numThreads );
	Geometry.Solver.accuracy( self.accuracy );
	Geometry.Solver.max_steps( self.maxSteps );
end
--===========================================================================--

--===========================================================================--
--设置信号源
function MSRCSSolver:set_signal()
	self:update_parameters_from_ui()	
	self:init_parameters()
	local sig = Geometry.object( "pulse" , 'signal' );
	if sig == nil then sig = Geometry.NewGaussPulse("pulse") end
	sig:freq(self.src_min_freq,self.src_max_freq);
	self.sig = sig;
end
--===========================================================================--


--===========================================================================--
--设置参数表
function MSRCSSolver:create_paras()
	Geometry.Parameters.add_variable("incident_angle","0","方位角: zx平面的夹角")
	Geometry.Parameters.add_variable("polar_angle","0",'极化角,垂直极化VV[0],水平极化HH[90]')
	Geometry.Parameters.add_variable("dfarbox","10",'远场盒子与几何结构距离')
	Geometry.Parameters.add_variable("dext","20",'入射源与几何结构距离')
	Geometry.Parameters.add_variable("elevation_angle","0",'俯仰角:与xy平面的夹角')	
end
function MSRCSSolver:set_paras()
	local lambda = c0/(self.meshFreq * Geometry.ref_units_freq() ) / Geometry.ref_units_dim();
	Geometry.Parameters.set_variable('dext',''..lambda/4);
	Geometry.Parameters.set_variable('dfarbox',''..lambda/8);

	local angs = self.scan_angles;
	local eang = self.elevationAngle;	
	local ang = angs[1];
	local polar = self.polars[1];
	
	if polar == 'HH' then
		Geometry.Parameters.set_variable("polar_angle","90")
	else
		Geometry.Parameters.set_variable("polar_angle","0")
	end
	Geometry.Parameters.set_variable('incident_angle',''..ang);
	
	Geometry.Parameters.set_variable('elevation_angle',''..eang);
	
	Geometry.Parameters.change_variable_sweep_state("incident_angle",true)
	
	Geometry.Parameters.change_variable_sweep_values("incident_angle",self.angleList1)
		
	Geometry.Parameters.change_variable_sweep_state("polar_angle",true)
	
	Geometry.Parameters.change_variable_sweep_values("polar_angle",self.polar_angles)

	Geometry.Parameters.valuate()
	
	--print( Gallop.ParametersSweep.index );
	
	Gallop.ParametersSweep:change_solver_index('FDTD');
	
	Gallop.ParametersSweep:update_solver_list_to_ui();
	
	local preStr=[[	
-----------------------------------------------------------------------
--参数扫描前处理函数
function prerun(self)
	Gallop.MSRCSApp:initSolver();
end
-----------------------------------------------------------------------
]]

	local stepStr=[[	
-----------------------------------------------------------------------
--每一步扫描过程执行函数
function step(self,idx)
	--保存当前视图
	--self.view3D:saveSnapShot("view"..idx..".png")

	Gallop.MSRCSApp:preRunSolver(idx);

	--求解
	Gallop.Solver:runSolver();
	
	Gallop.MSRCSApp:postRunSolver(idx);	
		
end	
-----------------------------------------------------------------------
]]

	local postStr=[[	
-----------------------------------------------------------------------
--参数扫描后处理函数
function postrun(self)
end
-----------------------------------------------------------------------
]]

	Gallop.ParametersSweep:set_solver_settings( stepStr  );
	Gallop.ParametersSweep:set_pre_settings( preStr);
	Gallop.ParametersSweep:set_post_settings( postStr);
	
	---------------------------
	--设置透视视角
	Gallop.View:perspective_view();
	---------------------------	
	
	Geometry.synchronize();

end

--===========================================================================--


--===========================================================================--
--设置入射源
function MSRCSSolver:set_source()
	
	local airbox = Geometry.object( "airbox" , 'geometry' );
	
	print( "create srouce")	
	-------------------------------------
	local angs = self.scan_angles;
	local eang = self.elevationAngle;	
	local ang = angs[1];
	local polar = self.polars[1];
	
	local freqmin = self.src_min_freq; --����Դ��ʼƵ��
	local freqmax = self.src_max_freq; --����Դ��ֹƵ��
	local dsrc = 0;

	assert(freqmin,"freqmin is not set in source function(.source_info.freqmin_)");
	assert(freqmax,"freqmax is not set in source function(.source_info.freqmax_)");
	assert(type,"src type is not set in source function(self.type_)");
	-------------------------------------
	self:set_signal();
	
	-------------------------------------
	--Source
	local src= Geometry.object( "PlaneWave" , 'source' );
	if src == nil then
		src =  Geometry.NewPlaneWaveSrc("PlaneWave");
		src :signal(self.sig)
		Geometry.AddSrc(src)
	end
	src :polarization_angle('polar_angle')


	src :pt1(self.bbox:xmin()..'-dext', self.bbox:ymin()..'-dext', self.bbox:zmin()..'-dext')
	src :pt2(self.bbox:xmax()..'+dext', self.bbox:ymax()..'+dext', self.bbox:zmax()..'+dext')
	
	src :signal(self.sig)
	src :direction(forward)
	src :point_size(2)

	src:enable_plane(yx)
	src:enable_plane(yz)
	src:enable_plane(zy)
	src:enable_plane(xz)
	src:enable_plane(zx)
	src:load_identity_matrix()
	src:rotate(yAxis,'-elevation_angle-90')	
	src:rotate(zAxis,'incident_angle')
	src:translate( self.bbox:xmin()+self.bbox:xsize()/2,
			     self.bbox:ymin()+self.bbox:ysize()/2,
			     self.bbox:zmin()+self.bbox:zsize()/2 )
	src :outline_width(1.5)	
end
--===========================================================================--


--===========================================================================--
--设置远场探测盒子
function MSRCSSolver:set_farbox()
	print( "create farbox")	
	local strFreq="";
	for k,v in pairs (self.probe_freq) do
		strFreq = strFreq..v..";"
	end
	--print('strFreq:',strFreq);
	---------------------------
	--FarField Box
	local fbox= Geometry.object( "fbox" , 'probe' );
	if fbox == nil then
		fbox =  Geometry.NewNear2FarFieldBox("fbox");
		Geometry.AddProbe(fbox)
	end
	fbox :signal(self.sig)

	fbox :pt1(self.bbox:xmin()..'-dfarbox',self.bbox:ymin()..'-dfarbox',self.bbox:zmin()..'-dfarbox')
	fbox :pt2(self.bbox:xmax()..'+dfarbox', self.bbox:ymax()..'+dfarbox',self.bbox:zmax()..'+dfarbox')
	fbox :angle_theta('90-elevation_angle','90-elevation_angle',1)
	fbox :angle_phi('incident_angle'..'-180', 'incident_angle'..'+180', 721)
	 fbox :freq(strFreq)
	-- farbox :is_point(true)
	-- farbox :is_outline(true)
	 fbox :is_fill(false)
	----------------------------
end
--===========================================================================--

--===========================================================================--
--添加近场探测面
function MSRCSSolver:set_nearfields()
	print( 'set nearfields' )
	if self.bSaveNearfields then
		local strFreq="";
		for k,v in pairs (self.probe_freq) do
			strFreq = strFreq..v..";"
		end
		local probe = Geometry.object( "nearfields" , 'probe' );
		if probe == nil then 
			probe = Geometry.NewSurfaceProbe("nearfields") 
			Geometry.AddProbe(probe);
		end		
		local bbox = self.bbox;
		probe :freq(strFreq)
		probe:fields_types(ex,ey,ez)
		probe:pt1( bbox:xmin() .. '-dext', bbox:ymin() .. '-dext',   tostring((bbox:zmin()+bbox:zmax())/2) );
		probe:pt2( bbox:xmax() .. '+dext', bbox:ymax() .. '+dext',tostring((bbox:zmin()+bbox:zmax())/2) );
		if self.sig == nil then
			self:set_signal();
		end
		probe:signal(self.sig)
	else
		Geometry.remove_object( "nearfields" , 'probe' );
	end

end
--===========================================================================--

--===========================================================================--
--设置空气盒子
function MSRCSSolver:set_airbox()
	local bbox = Geometry.bbox()	
	assert( bbox:size() > 0, '没有任何几何结构' );
	
	local airbox = Geometry.object( "airbox" , 'geometry' );
	if airbox == nil then airbox = Geometry.NewBrick({name="airbox",is_fill=false}) end
	
	local objlist = Geometry.objects("shape");
	Geometry.remove_all_objects( "shapes" );
	Geometry.AddShape(airbox)
         for k,v in pairs ( objlist ) do
		if v:name() ~= "airbox"  then
			Geometry.AddShape(v)
		end
	end
	
	local objlist = Geometry.objects("shape");
	bbox = objlist[2]:bbox();
	for k=3,#objlist do 
		bbox:add( objlist[k]:bbox() );
	end
	
	airbox:pt1( bbox:xmin() ..'-dext', bbox:ymin()..'-dext', bbox:zmin() ..'-dext');
	airbox:pt2( bbox:xmax()..'+dext', bbox:ymax()..'+dext',bbox:zmax() ..'+dext');	
	
	self.bbox =  bbox;
end
--===========================================================================--

--===========================================================================--
--设置抓屏器
function MSRCSSolver:set_grabber()
	local bbox = Geometry.bbox()	
	assert( bbox:size() > 0, '没有任何几何结构' );
	
	local grabber = Geometry.object( "grabber" , 'grabber' );
	if grabber == nil then 
		grabber = Geometry.NewGrabber({name="grabber"}) 
		local cm = Geometry.CGLColorMap:new("Jet");
		cm:min(0)
		Gallop.View:get3DView():perspective();
		local camera = Gallop.View:get3DView():camera();
		grabber:camera(camera);
		grabber:add_slice(cm,scalar_e,xy,bbox:zcenter(),0,false,'xy 平面')
		grabber:add_slice(cm,scalar_e,zx,bbox:ycenter(),0,false,'xz 平面')
		Geometry.AddTransientFieldsGrabber(grabber)	
	end
end
--===========================================================================--

--===========================================================================--
--创建入射角示意图
function MSRCSSolver:create_directions(bbox)

	---------------------------
	--创建显示点
	local pts = Geometry.object("directions","shape");
	if pts == nil then 
		pts = Geometry.NewPointSet("directions");
		Geometry.AddShape(pts);
	end
	pts:clear();
	local bbox = self.bbox;
	--local pts = Geometry.NewPointSet();
	local s = bbox:size()*0.5;
	local xc = (bbox:xmin()+bbox:xmax())/2.0
	local yc = (bbox:ymin()+bbox:ymax())/2.0
	local zc = (bbox:zmin()+bbox:zmax())/2.0
	
	local eang = self.elevationAngle * pi/180
	for _,ang in pairs(self.scan_angles) do		
		pts:insert( s * math.cos( ang *pi/ 180 ) * math.cos( eang )+ xc,
			        s * math.sin( ang *pi/ 180 ) * math.cos( eang )+ yc,
			        s * math.sin( eang ) + zc,
	                       -s/20*math.cos( ang *pi/ 180 )  * math.cos( eang ), 
			       -s/20*math.sin( ang *pi/ 180 )  * math.cos( eang ),
			       -s/20 * math.sin( eang )	);
	end
	pts:point_size(8)
	pts:fill_color(1,0,0)
	
	local axis = Geometry.object("incident","shape");
	if axis == nil then 
		axis = Geometry.NewAxis({name="incident",xName="E",yName="H",zName="k"});
		Geometry.AddShape(axis);
	end
	axis:load_identity_matrix();
	axis:scale(s/5,s/5,s/5)
	axis:rotate(zAxis,'polar_angle');
	axis:rotate(yAxis,-90);
	axis:translate(s,0,0);
	axis:rotate(yAxis,'-elevation_angle');	
	axis:rotate(zAxis,'incident_angle');	
	axis:translate(xc,yc,zc);
end
--===========================================================================--



--===========================================================================--
--检查目录是否为 RCS 工程
function MSRCSSolver:check_MonoStaticRCS_project()

	print( 'check project' )
	local fullpath =  Geometry.get_project_path();
	local stem =  Geometry.get_project_stem();
	print(fullpath,stem)
	
	local filename = getFilenameWithoutExt(fullpath);
	-- filename = unity.file_name(fullpath)
	
	print(fullpath,filename)
		
	if  string.match(filename, "RCS%-([HV][HV])%-ang%((.*)%)" ) ~= nil then
		local ppath = strippath(fullpath);
		local projectName = string.match(ppath, "MonoStaticRCS%-(.*)" );
		if projectName~=nil then		
			local pppath = unity.parent_path(ppath);		
			print(ppath, pppath, projectName);			
			self.path =  pppath;	
			self.rcsProjectName = projectName;	
			self.resultsPath = self.path .. "/MonoStaticRCS-".. self.rcsProjectName..'/';
			self.rcsProjectStem = self.path .. '/' .. self.rcsProjectName;	
			Geometry.set_path( self.path .. '/' .. self.rcsProjectName ..'.gap' );
			 -- self:update_parameters_to_ui()
			 self:update_results_path_to_ui()
		end
	end
	
	return false;
end
--===========================================================================--




function MSRCSSolver:set_calculate_parameters()
	print( "set calculation parameters" );		
	Gallop.ParametersSweep:clear_all_results();
	self:create_calculation_model()
	self.binit = true;
end

function MSRCSSolver:clean_results()
	assert(self.binit, '模型未初始化' )
	assert(self.path, '路径为空' )
-- self.strippath .. "/MonoStaticRCS-".. self.filename ..'/'

	-- print( self.strippath .. "/MonoStaticRCS-".. self.filename )
	-- print(lfs.rmdir( self.strippath .. "/MonoStaticRCS-".. self.filename ..'/' ));
	assert( unity.remove( self.path ) );
	
	unity.mkdir(self.path)
	unity.mkdir(self.resultsPath)
	unity.mkdir(self.gapsPath)
	
	--assert( unity.mkdir( self.resultsPath ) );

	-- assert( self.clean_results_impl( self.path ) , '路径不存在')
end

function MSRCSSolver:find_results()
	self.model_runned = {}
	self.model_unrunned = {}
	for k,v in pairs (self.model) do
		 --local gapPath = v.path .. "/" .. v.name..".gap";
		 local gapPath = v.path .. v.name..".gap";
		 print( "Try to read gap file:", gapPath )
		 -- v:init_results()
		 local flag = false;
		 if file_exists( gapPath ) then
			print('clear');
			Geometry.clear_all();
			print('load');
			Geometry.LoadGeometry (  gapPath )
			print('synchronize');
			Geometry.synchronize();
			v.results:read_from_model();	
			local valid = v.results:get_mono_RCS() 
			if  valid  and v.scan_angle == v.results.scan_angle_gap then 
				 table.insert( self.model_runned, v )
				 flag = true;
			end
		end
		if not flag then table.insert( self.model_unrunned, v ) end
		
		self:run_model_post();
	end
	
end




function MSRCSSolver:run_pond()
	print('run pond')
	assert(self.binit, '模型未初始化' )		 
	Gallop.ParametersSweep:run_sweep()
end


function MSRCSSolver:refresh_figs()
	self:run_model_post()
end

function MSRCSSolver:export_data(path)
     print("Export data:",path)
     -- self.rcsView:exportData(path)
  	local nf = #self.probe_freq;
	local freq = self.probe_freq;   
    local file = io.open(unity.utf8_to_local(path), "w")

    if #self.xx1 > 0 then
	    file:write( "phi[deg]\t" );
    end
    for ii=1,#self.yys do
    	if #self.xx1 == #self.yys[ii][1].data and #self.xx1 > 0 then
		file:write( self.yys[ii][1].label, "\t" );
	end
     end
     if #self.xx2 > 0 then
	    file:write( "phi[deg]\t" );
     end
     for ii=1,#self.yys do
       if #self.xx2 == #self.yys[ii][2].data and #self.xx2 > 0 then
		file:write( self.yys[ii][2].label, "\t" );
	end
    end
    file:write( "\n" );
	
	for tt=1, math.max( #self.xx1, #self.xx2 )  do
		if #self.xx1 > 0 then
			file:write( self.xx1[tt],"\t")
		end
		for ii=1,nf do
		     if #self.xx1 == #self.yys[ii][1].data and #self.xx1 > 0 then
			  file:write( self.yys[ii][1].data[tt], "\t" );
		     end
		end
		
		if #self.xx2 >= tt then
			file:write( self.xx2[tt],"\t")
			for ii=1,nf do     
			     if #self.xx2 == #self.yys[ii][2].data and #self.xx2 > 0 then
				  file:write( self.yys[ii][2].data[tt], "\t" );
			     end
			end
		end

		
		file:write( "\n" );
	end	
	
	
	file:close()
	
end



function MSRCSSolver:export_fields_data(path)
    print("Export data:",path)
     -- self.rcsView:exportData(path)
    local nf = #self.probe_freq;
    local freq = self. probe_freq;   
    local file = io.open(unity.utf8_to_local(path), "w")

    ---------------------------------------------------
    --File Header
    if #self.xx1 > 0 then
	    file:write( "phi[deg]\t" );
    end
    for ii=1,#self.yys do
    	if #self.xx1 == #self.yys[ii][3].data and #self.xx1 > 0 then
		file:write( self.yys[ii][3].label..'[real]', "\t" );
		file:write( self.yys[ii][3].label..'[imag]', "\t" );
	end
     end
     for ii=1,#self.yys do
    	if #self.xx1 == #self.yys[ii][5].data and #self.xx1 > 0 then
		file:write( self.yys[ii][5].label..'[real]', "\t" );
		file:write( self.yys[ii][5].label..'[imag]', "\t" );
	end
     end
     if #self.xx2 > 0 then
	    file:write( "phi[deg]\t" );
     end
     for ii=1,#self.yys do
       if #self.xx2 == #self.yys[ii][4].data and #self.xx2 > 0 then
		file:write( self.yys[ii][4].label..'[real]', "\t" );
		file:write( self.yys[ii][4].label..'[imag]', "\t" );
	end
    end
        
    for ii=1,#self.yys do
       if #self.xx2 == #self.yys[ii][6].data and #self.xx2 > 0 then
		file:write( self.yys[ii][6].label..'[real]', "\t" );
		file:write( self.yys[ii][6].label..'[imag]', "\t" );
	end
    end
    file:write( "\n" );
    ---------------------------------------------------
	
	for tt=1, math.max( #self.xx1, #self.xx2 )  do
		if #self.xx1 > 0 then
			file:write( self.xx1[tt],"\t")
		end
		for ii=1,nf do
		     if #self.xx1 == #self.yys[ii][3].data and #self.xx1 > 0 then
			  file:write( self.yys[ii][3].data[tt]:real(), "\t" );
			  file:write( self.yys[ii][3].data[tt]:imag(), "\t" );
			  file:write( self.yys[ii][5].data[tt]:real(), "\t" );
			  file:write( self.yys[ii][5].data[tt]:imag(), "\t" );
		     end
		end
		
		if #self.xx2 >= tt then
			file:write( self.xx2[tt],"\t")
		end
		for ii=1,nf do     
		     if #self.xx2 == #self.yys[ii][4].data and #self.xx2 > 0 then
			  file:write( self.yys[ii][4].data[tt]:real(), "\t" );
			  file:write( self.yys[ii][4].data[tt]:imag(), "\t" );
			  file:write( self.yys[ii][6].data[tt]:real(), "\t" );
			  file:write( self.yys[ii][6].data[tt]:imag(), "\t" );
		     end
		end
		
		file:write( "\n" );
	end	
	
	
	file:close()
	
end

function MSRCSSolver:save_pngs(path)
	print("Save figure:",path)
	self.rcsView:savePng(path)
end

function MSRCSSolver:run_model_post()
	
	self.xx1 = nl.new_vector();
	self.xx2 = nl.new_vector();
	self.yys = {};
	local nf = #self.probe_freq;
	local freq = self.probe_freq;
	for ii=1,nf do
	    self.yys[ii] = { {data=nl.new_vector(),label = "Freq="..freq[ii].."[GHz]-HH"},
	                           {data=nl.new_vector(),label = "Freq="..freq[ii].."[GHz]-VV"} ,
				   {data=nl.new_cvector(),label = "Freq="..freq[ii].."[GHz]-Etheta-HH"},
				   {data=nl.new_cvector(),label = "Freq="..freq[ii].."[GHz]-Etheta-VV"},
				   {data=nl.new_cvector(),label = "Freq="..freq[ii].."[GHz]-Ephi-HH"},
				   {data=nl.new_cvector(),label = "Freq="..freq[ii].."[GHz]-Ephi-VV"}};
	end
	
	
	for k,model in pairs( self.model_runned ) do
		if model.polar == "HH" then
			self.xx1:add( model.scan_angle )
			for ii=1,nf do			
				self.yys[ii][1].data:add( model.results.monoRCS[ii] )			
				--self.yys[ii][3].data:add( model.results.etheta[ii] )			
				--self.yys[ii][5].data:add( model.results.ephi[ii] )			
			end		
		end
	end
	
	for k,model in pairs( self.model_runned ) do
		if model.polar == "VV" then
			self.xx2:add( model.scan_angle )
			for ii=1,nf do			
				self.yys[ii][2].data:add( model.results.monoRCS[ii] )			
				--self.yys[ii][4].data:add( model.results.etheta[ii] )			
				--self.yys[ii][6].data:add( model.results.ephi[ii] )			
			end		
		end
	end
	
	if self.rcsView == nil then return; end
	
	self:init_rcs_plot();
	
	self.rcsView:clearGraphs();
	
	for ii=1,nf do
	     --print( yys[ii] )
	     if #self.xx1 == #self.yys[ii][1].data and #self.xx1 > 0 then
		self.rcsView:addGraph(self.xx1,self.yys[ii][1].data, self.yys[ii][1].label)	    
	     end
	     
	     if #self.xx2 == #self.yys[ii][2].data and #self.xx2 > 0 then
		self.rcsView:addGraph(self.xx2,self.yys[ii][2].data, self.yys[ii][2].label)	    
	     end
	end
	
	
	self.rcsView:rescaleAxes();
	
end


function MSRCSSolver:initSolver()
	if self.rcsView then
		self.rcsView:clearGraphs()
		self.rcsView:rescaleAxes();
	end
	
	if self.farfieldView then
		self.farfieldView:clearGraphs()
		self.farfieldView:rescaleAxes()
	end
	
	self.results={};	
	self:get_path_from_project();
end


function MSRCSSolver:preRunSolver(idx)

	function index( names, name )
		for k,v in pairs(names) do
			if v==name then
				return k
			end
		end
	end
	
	local names = Gallop.ParametersSweep.names;
	local polar_angle = 0;
	if index(names,'polar_angle') ~= nil then
		polar_angle = Gallop.ParametersSweep.paraList[idx][index(names,'polar_angle')];
	end
	
	local polar = 'VV'
	if nl.abs( polar_angle - 90) < 1e-3 then
		polar = 'HH';
	end
	local scan_angle = Gallop.ParametersSweep.paraList[idx][index(names,'incident_angle')];
        self.curr_lable = 'angle-'..scan_angle..' polar-'..polar;
	
	local grabber = Geometry.objects('Grabber');
	if grabber ~= nil and #grabber > 0 then
		grabber[1]:name('Grabber('.. self.curr_lable .. ')');
	end
end

function MSRCSSolver:postRunSolver(idx)
	local RCSPost = require"RCS.luaRCSPost"
	local rcs = RCSPost:new();
	rcs:read_from_model();
	print( "get mono RCS..." )	
	rcs:get_mono_RCS();	
	print( "plot farfields..." )	
	rcs.view = self.farfieldView
	rcs:add_phi_curves(rcs.freq_idx,
				      rcs.theta_idx,
				      rcs.phi_idx,
							   {"RCS-Total"})
							   
	function index( names, name )
		for k,v in pairs(names) do
			if v==name then
				return k
			end
		end
	end
	
	local names = Gallop.ParametersSweep.names;
	rcs.scan_angle = Gallop.ParametersSweep.paraList[idx][index(names,'incident_angle')];
	rcs.polar_angle = 0;
	if index(names,'polar_angle') ~= nil then
		rcs.polar_angle = Gallop.ParametersSweep.paraList[idx][index(names,'polar_angle')];
	end
	
	rcs.polar = 'VV'
	if nl.abs( rcs.polar_angle - 90) < 1e-3 then
		rcs.polar = 'HH';
	end
	
	--print( 'elevation_angle state:',Gallop.Parameters.get_variable_sweep_state('elevation_angle')  );
	if Gallop.Parameters.get_variable_sweep_state('elevation_angle') == true then
		rcs.phi_angle = Gallop.ParametersSweep.paraList[idx][index(names,'elevation_angle')];
	end
	--print(rcs.phi_angle)
	--self.results[idx] = rcs;

	self.results[idx] = {};
	self.results[idx]['scan_angle'] = rcs.scan_angle;
	self.results[idx]['polar'] = rcs.polar;
	local nf = #self.probe_freq;
	self.results[idx].monoRCS = {};
	for ii=1,nf do
		self.results[idx].monoRCS[ii]  = rcs.monoRCS[ii];
	end
	
	--strResults = dump(self.results,'results = ');
	--print(strResults);
	
	print( "plot monoRCS..." )

	self:run_model_post1();
	
	print( "save farfields to file..." )
	local fbox = Geometry.farbox_list();
	if #fbox >= 1 then
		--"RCS%-([HV][HV])%-ang%((.*)%)%.txt"
		local phistr = '';
		if Gallop.Parameters.get_variable_sweep_state('elevation_angle') == true then
			phistr = '-phi(' .. rcs.phi_angle .. ')';
		end
		fbox[1]:save( (self.resultsPath)..'RCS-'..rcs.polar..'-'..'ang('..rcs.scan_angle..')'..phistr..'.txt', 'RCS(dBsm)' )
	end
	
	print( "save monoRCS to file..." )
	self:export_fields_data( self.stemPath .. '-fields.txt' );
	self:export_data( self.stemPath .. '-msRCS.txt' );
	
	print( "post calculate finished, idx = [".. idx .. "]\n" )
	
	self:update_progress_bar( idx / #Gallop.ParametersSweep.paraList * 100 );
end

function MSRCSSolver:get_rcs_string()
	for k,model in pairs( self.results ) do
		if model.polar == "HH" then
			self.xx1:add( model.scan_angle )
			for ii=1,nf do			
				self.yys[ii][1].data:add( model.monoRCS[ii] )			
				self.yys[ii][3].data:add( model.etheta[ii] )			
				self.yys[ii][5].data:add( model.ephi[ii] )			
			end		
		end
	end
end

function MSRCSSolver:run_model_post1()
	
	self.xx1 = nl.new_vector();
	self.xx2 = nl.new_vector();
	self.yys = {};
	local nf = #self.probe_freq;
	local freq = self.probe_freq;
	for ii=1,nf do
	    self.yys[ii] = { {data=nl.new_vector(),label = "Freq="..freq[ii].."[GHz]-HH"},
	                           {data=nl.new_vector(),label = "Freq="..freq[ii].."[GHz]-VV"} ,
				   {data=nl.new_cvector(),label = "Freq="..freq[ii].."[GHz]-Etheta-HH"},
				   {data=nl.new_cvector(),label = "Freq="..freq[ii].."[GHz]-Etheta-VV"},
				   {data=nl.new_cvector(),label = "Freq="..freq[ii].."[GHz]-Ephi-HH"},
				   {data=nl.new_cvector(),label = "Freq="..freq[ii].."[GHz]-Ephi-VV"}};
	end
	
	
	for k,model in pairs( self.results ) do
		if model.polar == "HH" then
			self.xx1:add( model.scan_angle )
			for ii=1,nf do			
				self.yys[ii][1].data:add( model.monoRCS[ii] )					
			end		
		end
	end
	
	for k,model in pairs( self.results ) do
		if model.polar == "VV" then
			self.xx2:add( model.scan_angle )
			for ii=1,nf do			
				self.yys[ii][2].data:add( model.monoRCS[ii] )					
			end		
		end
	end
	
	if self.rcsView == nil then return; end
	
	self:init_rcs_plot();
	
	self.rcsView:clearGraphs();
	
	for ii=1,nf do
	     --print( yys[ii] )
	     if #self.xx1 == #self.yys[ii][1].data and #self.xx1 > 0 then
		self.rcsView:addGraph(self.xx1,self.yys[ii][1].data, self.yys[ii][1].label)	    
	     end
	     
	     if #self.xx2 == #self.yys[ii][2].data and #self.xx2 > 0 then
		self.rcsView:addGraph(self.xx2,self.yys[ii][2].data, self.yys[ii][2].label)	    
	     end
	end
	
	
	self.rcsView:rescaleAxes();
	
end

function MSRCSSolver:init_rcs_plot()
	 self.rcsView.xAxis:setProperty( {name="扫描角度 φ [°]"} )
	 self.rcsView.yAxis:setProperty( {name="单站RCS [dBsm]"} )
	 self.rcsView:rescaleAxes();
end


-----------------------------------------------------------------------------------------------------------------------------
--遍历文件名，获得固定格式文件名的rcs文件名称
function MSRCSSolver:read_results_gui()
	self:update_results_path_from_ui();
	self:read_results( self.resultsPath )
end
-----------------------------------------------------------------------------------------------------------------------------


-----------------------------------------------------------------------------------------------------------------------------
--遍历文件名，获得固定格式文件名的rcs文件名称
function MSRCSSolver:read_results(path)
	print('Read results from:', unity.local_to_utf8(path));	
	--print('1:', Geometry.get_project_path() )

	self.results_files={};
	-- 先尝试匹配包含 phi 的字符串
	local patternWithPhi = "RCS%-([HV][HV])%-ang%(([^)]*)%)%-phi%(([^)]*)%)%.txt"
	-- 如果上面的模式不匹配，再尝试匹配这个模式
	local patternWithoutPhi = "RCS%-([HV][HV])%-ang%(([^)]*)%)%.txt"

	unity.listMatchingFilesInDirectory(path, patternWithPhi, function(filepath, polar, angle, phi)
	    phi = phi or "0"  -- 如果 phi 不存在，将其设置为 "0"（在回调内部进行的检查）
	    print(unity.local_to_utf8(filepath), polar, angle, phi)
	    table.insert( self.results_files, { path=filepath, polar=polar,angle=angle; } )
	end)
	unity.listMatchingFilesInDirectory(path, patternWithoutPhi, function(filepath, polar, angle, phi)
	    phi = phi or "0"  -- 如果 phi 不存在，将其设置为 "0"（在回调内部进行的检查）
	    print(unity.local_to_utf8(filepath), polar, angle, phi)
	    table.insert( self.results_files, { path=filepath, polar=polar,angle=angle; } )
	end)
	self:parsers_results_files();	
	--print('3:' ,Geometry.get_project_path() )

end
-----------------------------------------------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------------------------------------------
--解析rcs文件：利用RCSPost脚本读取
function MSRCSSolver:parsers_results_files()
	self.model_runned = {}
	self.model_unrunned = {}
	self.results={}
	for k,v in pairs (self.results_files) do	
		local ra = RCS:new( { 
					name = self.name.."-"..v.polar.."-ang("..v.angle..")";
					polar = v.polar;						
					scan_angle = tonumber(v.angle);
					} )
		 ra:init_results();
			 
		 local texPath = v.path;
		 -- print( "Try to read txt file:", texPath )
		 -- print( "angle:", ra.scan_angle )
		 local flag = false;
		 if file_exists( texPath ) then
			ra.results:read_from_file(texPath);	
			local valid = ra.results:get_mono_RCS_from_file() 
			-- print_table(ra.results.theta_idx) 
			assert(#ra.results.theta_idx==1, "The results contains multi thetas");
			-- assert(tonumber(ra.results.theta_idx[1])==90, "Theta ~= 90");
			 print(ra.results.freq_array);
			self.probe_freq = ra.results.freq_array;
			
			self.results[k] = {};
			self.results[k]['scan_angle'] = tonumber(v.angle);
			self.results[k]['polar'] = v.polar;
			local nf = #self.probe_freq;
			self.results[k].monoRCS = {};
			for ii=1,nf do
				self.results[k].monoRCS[ii]  = ra.results.monoRCS[ii];
			end
		end	
		table.insert(self.model_runned,ra);
		self:run_model_post();
	end	
	self:run_model_post1();
end
-----------------------------------------------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------------------------------------------
--清除图像
function MSRCSSolver:clearGraphs()
	if self.farfieldView then
		self.farfieldView:clearGraphs()
	end
	if self.rcsView then
		self.rcsView:clearGraphs()
	end
end
-----------------------------------------------------------------------------------------------------------------------------


function MSRCSSolver:add_view()
	if self.console~=true then
		local gallop = require "QGMainWindow"
		self.mw = gallop.getMainWindow();
		self.rcsView = self.mw:create2DView("View2D");
	end
end

function MSRCSSolver:select_active_view()
	if self.console~=true then
		local gallop = require"QGMainWindow"
		self.mw = gallop.getMainWindow();
		local view = self.mw:activeViewer2DChild();
		assert(self.mw:hasView(view)==true,"The active view is not a 2D viewer!")
		self.rcsView = view;
	end
end

return MSRCSSolver;